package com.kamkor.interviewer.server;

import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManager;
import javax.jdo.PersistenceManagerFactory;
import javax.jdo.Query;

import com.google.appengine.api.datastore.Text;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import com.kamkor.interviewer.client.InterviewService;
import com.kamkor.interviewer.shared.UserDetails;
import com.kamkor.interviewer.shared.InterviewDetails;
import com.kamkor.interviewer.shared.QuestionAnswerDetails;


/**
 *
 * @author kamkor
 */
@SuppressWarnings("serial")
public class InterviewServiceImpl extends RemoteServiceServlet 
implements InterviewService {
	
	private static final Logger LOG = Logger.getLogger(InterviewServiceImpl.class.getName());
	private static final PersistenceManagerFactory PMF =
	      JDOHelper.getPersistenceManagerFactory("transactions-optional");	

	@Override
	public UserDetails createInterview(InterviewDetails interviewDetails) {		
		PersistenceManager pm = getPersistenceManager();
		Interview interview = 
			new Interview(interviewDetails.getInterviewerName(),
					interviewDetails.getInterviewerInitials(),
					interviewDetails.getInterviewedName(),
					interviewDetails.getInterviewedInitials());	
			interview.setAdminKey(Utils.generateAdminKey(interview));
			interview.setUserKey(Utils.generateUserKey(interview));
			interview.setLastQAPostionNumber(new Long(0));
		try {		
			pm.makePersistent(interview);
			LOG.log(Level.INFO, "created interview "+ interview.getId() + 
					" "+ interview.getInterviewerName() +
					" "+ interview.getInterviewedName());
			return new UserDetails(interview.getId(), interview.getAdminKey(), interview.getUserKey());
		} finally {
			pm.close();
		}		
	}
	
	@Override
	public QuestionAnswerDetails createQuestionAnswer(Long interviewId, String question,
			String answer) {
		PersistenceManager pm = getPersistenceManager();		
		try {
			Interview interview = pm.getObjectById(Interview.class, interviewId);
			Long newLastQAPositionNumber = interview.getLastQAPostionNumber() + 1;
			interview.setLastQAPostionNumber(newLastQAPositionNumber);
			
			QuestionAnswer qa = new QuestionAnswer(interviewId, new Text(question), new Text(answer));
			qa.setPositionNumber(newLastQAPositionNumber);
			
			pm.makePersistent(qa);			
			pm.makePersistent(interview);
			QuestionAnswerDetails qaDetails = new QuestionAnswerDetails(qa.getId(), qa.getInterviewId(), qa.getQuestion().getValue(), qa.getAnswer().getValue());
			qaDetails.setPositionNumber(qa.getPositionNumber());
			LOG.log(Level.INFO, "created QuestionAnswer\n" +
					qaDetails.getAnswer() + 
					"\n" + qaDetails.getQuestion());			
			return qaDetails;
		} finally {
			pm.close();		
		}
	}

	/**
	 * @return QuestionAnswer list ordered by questionanswer number (question added first has number 0)
	 * 
	 */
	@SuppressWarnings("unchecked")
	@Override
	public List<QuestionAnswerDetails> getQuestionAnswer(Long interviewId) {
		PersistenceManager pm = getPersistenceManager();
		
		Query query = pm.newQuery(QuestionAnswer.class);
		query.setFilter("interviewId == interviewIdParam");
		query.setOrdering("positionNumber asc");
		query.declareParameters("Long interviewIdParam");				
		try {
			List<QuestionAnswer> results = (List<QuestionAnswer>) query.execute(interviewId);
			List<QuestionAnswerDetails> transformedResults = new ArrayList<QuestionAnswerDetails>(results.size());
			
			for(QuestionAnswer qa : results) {
				QuestionAnswerDetails qaDetails = new QuestionAnswerDetails(qa.getId(), qa.getInterviewId(), qa.getQuestion().getValue(), qa.getAnswer().getValue());
				qaDetails.setPositionNumber(qa.getPositionNumber());
				transformedResults.add(qaDetails);			
			}
			return transformedResults;			
		} finally {
			query.closeAll();
			pm.close();			
		}
	}
	
	@Override
	public void updateQuestionAnswer(List<QuestionAnswerDetails> list) {
		PersistenceManager pm = getPersistenceManager();
		List<QuestionAnswer> qaDatastoreList = new ArrayList<QuestionAnswer>(list.size());
		for(QuestionAnswerDetails qa : list) {			
			QuestionAnswer qaDatastore = new QuestionAnswer(qa.getId(), qa.getInterviewId(), new Text(qa.getQuestion()), new Text(qa.getAnswer()));
			qaDatastore.setPositionNumber(qa.getPositionNumber());
			qaDatastoreList.add(qaDatastore);
		}
		
		try {
			pm.makePersistentAll(qaDatastoreList);
		} finally {
			pm.close();
		}
	}	

	
	@Override
	public InterviewDetails getInterview(Long id) {
		PersistenceManager pm = getPersistenceManager();
		try {
			Interview interview = pm.getObjectById(Interview.class, id);
			return new InterviewDetails(interview.getInterviewerName(), interview.getInterviewerInitials(), 
					interview.getInterviewedName(), interview.getInterviewedInitials());
		} finally {
			pm.close();
		}
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public List<InterviewDetails> getInterviews() {
		PersistenceManager pm = getPersistenceManager();
		try {
			Query query = pm.newQuery(InterviewDetails.class);
			query.setOrdering("id asc");			
			return (List<InterviewDetails>) query.execute();
		} finally {
			pm.close();
		}
	}
	
	@Override
	public void deleteQuestionAnswer(Long id) {
		PersistenceManager pm = getPersistenceManager();
		try {
			pm.deletePersistent(pm.getObjectById(QuestionAnswer.class, id));
		} finally {
			pm.close();
		}
	}
	
	/**
	 * verifies interviewer (admin)
	 * 
	 * @returns true if key is correct
	 */
	@Override
	public boolean authenticateInterviewer(Long interviewId, Long adminKey) {
		PersistenceManager pm = getPersistenceManager();		
		try {
			Interview interview = pm.getObjectById(Interview.class, interviewId);	
			return interview.getAdminKey().equals(adminKey) ? true : false;
		} finally {
			pm.close();
		}		
	}
	

	/** 
	 * verifies interviewed (user)
	 * 
	 * @returns true if key is correct
	 */
	@Override
	public boolean authenticateInterviewed(Long interviewId, Long key) {
		PersistenceManager pm = getPersistenceManager();
		try {
			Interview interview = pm.getObjectById(Interview.class, interviewId);
			return interview.getUserKey().equals(key) ? true : false;
		} finally {
			pm.close();
		}
	}
	
	@Override
	public String getRequestHost() {
		return getThreadLocalRequest().getRemoteHost();
	}
	
	private PersistenceManager getPersistenceManager() {
		return PMF.getPersistenceManager();
	}


}
